-
Notifications
You must be signed in to change notification settings - Fork 148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add completion settings (Hinterland mode, documentation, suppression) #315
Conversation
I guess I will have to write tests for that at some point... I guess I will do one for the documentation in completer behaviour tomorrow so that we have at least one test using the settings before we merge this. |
"title": "LSP features", | ||
"description": "Client-side features configuration", | ||
"$ref": "#/definitions/features", | ||
"default": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if the defaults
are actually preserved all the way down... it might just be the top-level object. would have to check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, they seem to be preserved - at least in the sense of being correctly displayed in the settings editor; how else can I specify them? properties
→ completion
and then default?
settings: ISettingRegistry.ISettings; | ||
|
||
constructor( | ||
public app: JupyterFrontEnd, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This signature is already way too complicated. A more common pattern would be to have a ILanguageServerManager.IOptions
which defined all these pieces, and didn't conflate the variable scopes (public/private) in the constructor. Putting this in a (new) tokens.ts
will help downstreams understand what the language server manager can provide to them.
The main advantage here is that it is easier to add a property to an unordered set of named arguments rather than getting the perfect ordering of many disparate types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get that there are a few advantages of IOptions
pattern, but it does not seem greatly useful for a function which gets called once ever (and with arguments that we do not control). Besides, having IOptions
here would just move the problem of relying on a specific ordering of arguments to the activate()
function (which already led to a hard-to-debug issue - explicit typing with a list of types is based on that lesson).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
advantages, off the top of my head:
- easier to document
- easier to extend
- better completion
- more like core
activate
is needfully the special case, at the application level, so that things can be replaced.
ILabShell, | ||
IStatusBar | ||
], | ||
activate: (app, ...args) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i see what you're doing here, and yes, relying on so many things is onerous. but this seems like a very roundabout way to leverage the type system... and basically guarantees that the signature, and therefore the API, will break the next time this changes. Sure, you're not returning this superobject yet, but this would all but need to be the public API.
my experience has been to minimize the number of external APIs that are actually called inside the manager class, and favor connecting to top-level signals in the extension.ts
. this centralizes the potential API surface to the best
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- not returning because activate has
void
signature - as long as the
requires
andas []
stay in sync this will not break (ideally there would be aconst TOKENS = [...]
ontype TOKENS = [...]
defined in a single line, but I could not get it working) - yes the public API will change the next time we add a token dependency, but is this a bad thing?
LSPExtension
is only meant to be used in the activate function (can document this). I see that I export it but maybe if I exported an interface with the things that are meant to be passed down, thenLSPExtension
would no longer be public. On the other hand, I do not feel convenient having the extra interface if I can just have an extension object. The extension class just seems so natural to have (and it to contain app and settings references)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quick note: 1 no longer the case in the refactor, this was my limited understanding.
@@ -44,20 +41,11 @@ export class FileEditorAdapter extends JupyterLabWidgetAdapter { | |||
} | |||
|
|||
constructor( | |||
extension: LSPExtension, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same thing here: when we start changing constructors, we should just go ahead and adopt an IOptions
someplace so the options can grow more organically over time. The closer we can start making <ActivityName>WidgetAdapter
invocation to be more regular, I think the happier we'll be...
'completer:invoke-file', | ||
connection_manager | ||
); | ||
super(extension, editor_widget, 'completer:invoke-file'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should probably collect all of our external command references someplace...
return this.get_obj()[setting]; | ||
} | ||
|
||
set(setting: string, value: any) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here, you could reus the T
from above, and always set to a Partial<T>
: fewer magic strings, and no looping (outside of here) to set multiple values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not understand. Could you throw me some example, plese?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'll see if i can dig something up. Basically, if you know T
, you can ask for setting: keyof T
, and then the value can be inferred by type inference. I think lumino
has some stuff like that.
) { | ||
this.app = extension.app; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if possible, we should try to keep references to the application itself to a minimum...
) { | ||
this.app = extension.app; | ||
this.rendermime_registry = extension.rendermime_registry; | ||
this.connection_manager = extension.connection_manager; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indeed, many of these things could just become dumb getters that wrap this.extension.X
(or this.language_server_manager.X
)
this.document_connected = new Signal(this); | ||
this.invoke_command = invoke; | ||
this.adapters = new Map(); | ||
this.status_message = new StatusMessage(); | ||
this.connection_manager = connection_manager; | ||
this.completion_settings = new LabFeatureSettings( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this seems like sort of a weird place to land this...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see https://github.com/krassowski/jupyterlab-lsp/pull/315/files#diff-768f6aea86149c0aa51e05111ea0968cR160. I don't like it either but seems the best thing to maintain separation of lab-specific and codemirror-specific code without major refactoring. I mean it should probably go like Feature = LabFeature + CMFeature + Settings (which are relevant to both) - I can work on it in a subsequent PR.
Thanks for the feedback! I will try to adress the points tomorrow. |
this is also a substantial rewrite... i mean, whatever, but it's going to get pretty headachey to start bringing the kernel branch back up to snuff. |
Implement completer icons and add a stub for themes system
Syntax highlighting
Fix statusbar message pooling data from all editors
Make code extractors and replacements modular
Try to use the most recent build of tectonic again
Features refactor
References
Implements #25, closes #314, addresses a long standing feature request by @simon-ritchie in early feedback here (the Hinterland mode).
Code changes
LSPExtension
to simplify passing stuff around (especially settings)IFeatureSettings
interface to allow isolate access to subset of settings by the features (implemented byLabFeatureSettings
)User-facing changes
Backwards-incompatible changes
JupyterLabWidgetAdapter
constructor was rewrittenChores